package perl.compiler.gui;

import java.awt.EventQueue;

import perl.lexical.classes.VariableElement;
import perl.lexical.classes.FunctionElement;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.border.EtchedBorder;

import perl.compiler.LexicalAnalyzer;
import perl.compiler.SyntaxAnalizer;
import perl.compiler.SemantycAnalizer;
import perl.compiler.utils.CodeLoader;
import perl.lexical.classes.Token;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.Map.Entry;

import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;

public class CompilerGUI extends JFrame {

	private static final long serialVersionUID = 1L;
	private JPanel contentPane;
	private JTextField txtCode;
	private LexicalAnalyzer lexicalAnalizer;
	private SyntaxAnalizer syntaxAnalizer;
	private SemantycAnalizer semantycAnalizer;
	private Map<Integer, Token> tokens;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {

					CompilerGUI frame = new CompilerGUI();
					frame.setVisible(true);

				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});

	}

	/**
	 * Create the frame.
	 */
	public CompilerGUI() {
		setTitle("PerlCompiler");
		setResizable(false);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 959, 699);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		contentPane.setLayout(null);

		JPanel panel = new JPanel();
		panel.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
		panel.setBounds(10, 11, 378, 639);
		contentPane.add(panel);
		panel.setLayout(null);

		JScrollPane scrollPane_1 = new JScrollPane();
		scrollPane_1.setBounds(10, 11, 358, 487);
		panel.add(scrollPane_1);

		final JTextArea sourceArea = new JTextArea();
		scrollPane_1.setViewportView(sourceArea);
		sourceArea.setToolTipText("Put your code here...");

		txtCode = new JTextField();
		txtCode.setText("code.txt");
		txtCode.setBounds(81, 510, 143, 20);
		panel.add(txtCode);
		txtCode.setColumns(10);

		JLabel sourceFileLabel = new JLabel("Source file:");
		sourceFileLabel.setBounds(10, 513, 81, 14);
		panel.add(sourceFileLabel);
		
		final JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
		final JTextArea analizeArea = new JTextArea();
		final JTextArea syntaxArea = new JTextArea();
		final JTextArea semantycArea = new JTextArea();
		// CREATE LEXICAL ANALIZER
		lexicalAnalizer = new LexicalAnalyzer();

		// LOAD CODE --------------
		JButton sourceLoadButton = new JButton("Load code");
		sourceLoadButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {

				try {
					sourceArea.setText("");
					for (StringBuilder str : CodeLoader.readFile(txtCode
							.getText())) {
						sourceArea.append(str.toString());
						sourceArea.append("\n");
					}
				} catch (IOException e) {
					JOptionPane.showMessageDialog(null, "Wrong file!");

				}

			}
		});
		sourceLoadButton.setBounds(251, 509, 115, 23);
		panel.add(sourceLoadButton);
		// -------------------------

		// LEXICAL ANALIZER
		JButton lexicalButton = new JButton("Lexical analization");
		lexicalButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				List<StringBuilder> source = getSource(sourceArea);
				try {
					
					tokens = new TreeMap<Integer, Token>();
					tokens = lexicalAnalizer.analize(source);
					printTokens(tokens, analizeArea);
					
					tabbedPane.setSelectedIndex(0);
				} catch (Exception e) {
					analizeArea.setText(e.getLocalizedMessage());
					//JOptionPane.showMessageDialog(null, e.getLocalizedMessage());

				}
			}
		});
		lexicalButton.setBounds(104, 542, 174, 20);
		panel.add(lexicalButton);
		
		JButton btnSyntaxAnalization = new JButton("Syntax analization");
		btnSyntaxAnalization.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				try {	
					syntaxAnalizer = new SyntaxAnalizer(tokens);
					syntaxAnalizer.analize();
					List<String> syntaxResult = syntaxAnalizer.getSyntaxLog();
					printSyntaxLog(syntaxResult, syntaxArea);
					
					tabbedPane.setSelectedIndex(1);
				} catch (Exception e) {
					syntaxArea.setText(e.getLocalizedMessage());
					tabbedPane.setSelectedIndex(1);
					//JOptionPane.showMessageDialog(null, e.getLocalizedMessage());

				  }
			}
		});
		btnSyntaxAnalization.setBounds(104, 568, 174, 20);
		panel.add(btnSyntaxAnalization);
		
		JButton button = new JButton("Semantyc analization");
		button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				try {
					semantycAnalizer = new SemantycAnalizer(tokens);
					semantycAnalizer.analize();
					
					Map<String, VariableElement> semantycVeriableResult = semantycAnalizer.getVariableElements();
					Map<String, FunctionElement> functionVeriableResult = semantycAnalizer.getFunctionElements();
					
					printSemanticVariableLog(semantycVeriableResult, semantycArea);
					printSemanticFunctionLog(functionVeriableResult, semantycArea);
					tabbedPane.setSelectedIndex(2);
				} catch (Exception e) {
					semantycArea.setText(e.getLocalizedMessage());
					tabbedPane.setSelectedIndex(2);
					//JOptionPane.showMessageDialog(null, e.getLocalizedMessage());

				  }
			}
		});
		button.setBounds(104, 594, 174, 20);
		panel.add(button);
		
		
		tabbedPane.setBounds(400, 11, 533, 639);
		contentPane.add(tabbedPane);
		
				JPanel panel_1 = new JPanel();
				tabbedPane.addTab("Lexical", null, panel_1, null);
				panel_1.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
				panel_1.setLayout(null);
				
						JScrollPane scrollPane = new JScrollPane();
						scrollPane.setBounds(12, 12, 488, 587);
						panel_1.add(scrollPane);
						
								analizeArea.setEditable(false);
								scrollPane.setViewportView(analizeArea);
								analizeArea.setLineWrap(true);
								
								JPanel panel_2 = new JPanel();
								panel_2.setLayout(null);
								panel_2.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
								tabbedPane.addTab("Syntax", null, panel_2, null);
								
								JScrollPane scrollPane_2 = new JScrollPane();
								scrollPane_2.setBounds(12, 12, 488, 587);
								panel_2.add(scrollPane_2);
								
								
								scrollPane_2.setViewportView(syntaxArea);
								
								JPanel panel_3 = new JPanel();
								panel_3.setLayout(null);
								panel_3.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
								tabbedPane.addTab("Semantyc", null, panel_3, null);
								
								JScrollPane scrollPane_3 = new JScrollPane();
								scrollPane_3.setBounds(12, 12, 490, 587);
								panel_3.add(scrollPane_3);
								
								
								scrollPane_3.setViewportView(semantycArea);
		// --------------------------

	}

	private List<StringBuilder> getSource(JTextArea textArea) {

		List<StringBuilder> source = new ArrayList<StringBuilder>();
		for (String line : textArea.getText().split("\n")) {
			source.add(new StringBuilder(line));
		}

		return source;
	}

	private void printTokens(Map<Integer, Token> tokens, JTextArea area) {

		area.setText("");
		area
				.setText("TokenClass"
						+ "\t\t"
						+ "Lexem"
						+ "\t"
						+ "row"
						+ "\t"
						+ "column"
						+ "\n"
						+ "-------------------------------------------------------------------------------------------------"
						+ "\n");

		for (Integer token : tokens.keySet()) {
			area.append(tokens.get(token).toString());
			area.append("\n");
		}
	}
	
	private void printSyntaxLog(List<String> log, JTextArea area) {

		area.setText("");
		area.setText("Syntax info: \n\n");

		for (String s : log) {
			area.append(s);
			area.append("\n");
		}
	}
	
	private void printSemanticVariableLog(Map<String, VariableElement> log, JTextArea area) {

		area.setText("Variables: \n");
		area
		.append("Name"
				+ "\t\t"
				+ "Type"
				+ "\t"
				+ "Nesting Level"
				+ "\t"
				+ "\n"
				+ "-------------------------------------------------------------------------------------------------"
				+ "\n");

		for(Entry<String, VariableElement> variable : log.entrySet()) {
			area.append(variable.getValue().toString());
			area.append("\n");
		}
		area
		.append("\n\n\n");
	}
	
	private void printSemanticFunctionLog(Map<String, FunctionElement> log, JTextArea area) {
		area.append("Procedures: \n");
		area
		.append("Name"
				+ "\t\t"
				+ "Number of parameters"
				+ "\n"
				+ "-------------------------------------------------------------------------------------------------"
				+ "\n");

		for(Entry<String, FunctionElement> function : log.entrySet()) {
			area.append(function.getValue().toString());
			area.append("\n");
		}
	}
}
